#include "stm32f10x.h"                  // STM32F1系列芯片外设库
#include "Serial.h"	                    // 串口功能相关声明（自定义头文件）
#include "opencv.h"                     // OpenCV通信相关声明（自定义头文件，含数据解析函数）

// 如果使用uC/OS操作系统，需要包含其头文件
#if SYSTEM_SUPPORT_OS
#include "includes.h"					// uC/OS操作系统头文件	  
#endif


// 重定向printf函数到串口，无需勾选use MicroLIB
#if 1
#pragma import(__use_no_semihosting)     // 禁止使用半主机模式（避免依赖IDE的调试环境）

// 标准库需要的文件结构体
struct __FILE 
{ 
	int handle;  // 文件句柄（此处未实际使用，仅为兼容标准库）
}; 

FILE __stdout;  // 标准输出流（用于printf）

// 重定义系统退出函数（避免半主机模式下的退出行为）
void _sys_exit(int x) 
{ 
	x = x;  // 空实现，防止程序异常退出
} 

// 重定义fputc函数，使printf输出到串口1
int fputc(int ch, FILE *f)
{ 	
	while((USART1->SR & 0X40) == 0);  // 等待发送缓冲区为空（TXE位为1）
	USART1->DR = (u8)ch;             // 将字符写入发送数据寄存器，通过串口1发送
	return ch;                        // 返回写入的字符
}
#endif


#if EN_USART1_RX   // 如果使能串口1接收功能，则编译以下代码

// 串口接收缓冲区，可存储USART_REC_LEN个字节（长度由宏定义）
u8 USART_RX_BUF[USART_REC_LEN];     

// 串口接收状态标志（16位）
// bit15：接收完成标志（0=未完成，1=完成）
// bit14：已接收0x0d（回车符）
// bit13~0：当前已接收的字节数
u16 USART_RX_STA = 0;               


/**
 * @brief  串口1初始化函数
 * @param  bound：波特率（如9600、115200等）
 * @retval 无
 */
void uart_init(u32 bound)
{
	// 使能串口1和GPIOA的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// 配置TX引脚（PA9）
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  // 复用推挽输出（串口发送需要复用功能）
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;        // 对应USART1的TX引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;// 输出速度50MHz
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	// 配置RX引脚（PA10）
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;    // 上拉输入（避免悬空，稳定接收）
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;       // 对应USART1的RX引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	// 配置串口1参数
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate = bound;             // 波特率（与OpenCV保持一致）
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  // 无硬件流控
	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;  // 同时使能发送和接收
	USART_InitStructure.USART_Parity = USART_Parity_No;      // 无校验位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;   // 1个停止位
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;  // 8位数据位
	USART_Init(USART1, &USART_InitStructure);  // 应用配置
	
	// 使能串口1的接收中断（RXNE：接收数据寄存器非空）
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	
	// 配置串口1中断的NVIC优先级
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;  // 串口1中断通道
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;     // 使能中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;  // 抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;     // 子优先级3
	NVIC_Init(&NVIC_InitStructure);  // 应用配置
	
	// 使能串口1
	USART_Cmd(USART1, ENABLE);
}


/**
 * @brief  串口1中断服务函数（处理接收中断）
 * @retval 无
 */
void USART1_IRQHandler(void)                
{
	u8 Res;  // 接收的字节数据
	
#if SYSTEM_SUPPORT_OS  // 如果支持操作系统，进入中断服务前通知系统
	OSIntEnter();    
#endif

	// 检查是否是接收数据寄存器非空中断（RXNE）
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  
	{
		Res = USART_ReceiveData(USART1);  // 读取接收的数据（从USART1->DR寄存器）
		
		// 将接收的字节传递给OpenCV数据解析函数（状态机处理，见opencv.h）
		Opencv_Receive_Data(Res);
		// 解析数据（实际在状态机完成一帧后才有效，此处提前调用不影响）
		Opencv_Data();
		
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);  // 清除接收中断标志位
		
		// 以下是通用串口接收逻辑（用于普通数据接收，与OpenCV解析可并行）
		if((USART_RX_STA & 0x8000) == 0)  // 若未接收完成
		{
			if(USART_RX_STA & 0x4000)  // 若已接收0x0d（回车符）
			{
				if(Res != 0x0a)  // 若下一个不是0x0a（换行符），则接收错误，重置状态
					USART_RX_STA = 0;
				else  // 接收到0x0a，标志接收完成（bit15置1）
					USART_RX_STA |= 0x8000;	
			}
			else  // 尚未接收0x0d
			{	
				if(Res == 0x0d)  // 若接收到0x0d，标记bit14
					USART_RX_STA |= 0x4000;
				else  // 普通数据，存入缓冲区并计数
				{
					USART_RX_BUF[USART_RX_STA & 0X3FFF] = Res;
					USART_RX_STA++;
					// 若缓冲区满，重置（防止溢出）
					if(USART_RX_STA > (USART_REC_LEN - 1))
						USART_RX_STA = 0;  
				}		 
			}
		}	
	} 

#if SYSTEM_SUPPORT_OS  // 如果支持操作系统，退出中断服务时通知系统
	OSIntExit();  											 
#endif
} 

#endif	// 结束EN_USART1_RX条件编译
